/**
* @brief 操作系统内核文件
* @author chenjl
* @date 2019.07.01
*/

#include "kerOs.h"
#include "OsConfigure.h"
#include "Kernel.h"
#include "KerEvent.h"
#include "kerMpu.h"
#include "DevsIO.h"

uint32 KernelTick = 0;
int32  curTaskId = 0;      ///<当前执行的任务编号，0为系统安全后台
uint16 KerCpuLoad = 0;

static void Kernel_TickTasks(TASK_CONTEXT *pTask);

#define SWITCH_TASK     (SCB->ICSR = SCB_ICSR_PENDSVSET_Msk)

void SysTick_Handler(void)
{
    KernelTick++;
    SWITCH_TASK;
    
    /**统计CPU负载*/
    if(curTaskId > 0)
    {
        KerCpuLoad++;
        if((KernelTick & 0x3ff) == 0)
        {
            kerCpuIdleMill = KerCpuLoad;
            KerCpuLoad = 0;
        }
    }
}

void SVC_Server(SVC_CONTEXT *pSvcContext)
{
    uint32 svc_num = ((char*)pSvcContext->pc)[-2];
    uint32 *p;
    switch(svc_num)
    {    
    case 0x13:
        p = (uint32*)pSvcContext->r0;
        switch(p[0])
        {
            case 1:
                pSvcContext->r0 = kerCreateEvent((char*)p[1]);
                break;
            case 2:
                kerWaitEvent(p[1],p[2]);
                break;
            case 3:
                kerSetEvent(p[1]);
                break;
            default:
                break;
        }
        break;
    case 0x12:
        switch(pSvcContext->r0)
        {
            case 1:
                pSvcContext->r0 = kerGetSystemTime();
                break;
            case 2:
                pSvcContext->r0 = KerGetCpuIdle();
                break;
            default:
                break;
        }    
        break;
    case 0x11:
        switch(pSvcContext->r0)
        {
            case 1:
                kerTaskWait(pSvcContext->r1);
                break;
            case 2:
                kerTaskWaitNxtPeriod();
                break;
            case 3:
                kerTaskDelay(pSvcContext->r1);
                break;
            case 4:
                kerTaskKill();
                break;
            default:
                break;
        }
        break;
    case 0x10:
        p = (uint32*)pSvcContext->r0;
        switch(p[0])
        {
            case 1:
                pSvcContext->r0 = kerDevOpen((char*)p[1],p[2]);
                break;
            case 2:
                pSvcContext->r0 = kerDevRead(p[1],(uint8*)p[2],p[3]);
                break;
            case 3:
                pSvcContext->r0 = kerDevWrite(p[1],(uint8*)p[2],p[3]);
                break;
            case 4:
                pSvcContext->r0 = kerDevCtrl(p[1],p[2],p[3]);
                break;
            default:
                pSvcContext->r0 = 0;
                break;
        }
        break;
    default:
        break;
    }
}

void HardFault_Handler(void)
{
    if(curTaskId > 0)
    {
        //任务发生异常,终止对应的任务
        taskConfigurations[curTaskId - 1].status = TASK_STATUS_INVALID;
        //切换任务的执行
        SWITCH_TASK;
    }
    else
    {
        //后台任务或内核异常，锁死(重启？)
        while(1)
        {
            __NOP();
        }
    }
    __ISB();
    __WFE();
}

/**
* @brief 判断是否需要切换
* @return 返回-1表示不切换任务，否则为新任务号
* 任务号从1开始，因为0表示后台任务
*/
int32 Kernel_isSwitching()
{
    int32 newIdx = Kernel_NextTask() + 1;
    if(newIdx == curTaskId)
    {
        /*不切换时，如果是任务，则更新执行时间*/
        if(newIdx > 0)
        {
            taskConfigurations[newIdx-1].touchtick = KernelTick;
        }
        return -1;
    }
    else
    {
        return newIdx;
    }
}

uint32 safeBgStackPtr = 0;

int32 Kernel_Active(int32 nwTask,uint32 oldpsp)
{
    int32 tid = curTaskId - 1;
    
    if(curTaskId == 0)
    {
        safeBgStackPtr = oldpsp;
    }
    else
    {
        taskConfigurations[tid].stack_ptr = oldpsp;
        
        if(*taskConfigurations[tid].stack_buttom != STACK_END_FLAG)
        {
            //栈溢出检测
            taskConfigurations[tid].status = TASK_STATUS_INVALID;
        }
        else
        {
            //正常退出时，旧任务切换为就绪状态
            if(taskConfigurations[tid].status == TASK_STATUS_RUNNING)
            {
                taskConfigurations[tid].status = TASK_STATUS_READY;
            }
        }
    }
    curTaskId = nwTask;
    if(curTaskId > 0)
    {
        //减1，是剔除后台安全序列索引0，并转换为任务列表索引
        tid = curTaskId - 1;
        //更新任务执行时刻标志
        taskConfigurations[tid].touchtick = KernelTick;
        //新任务切换为运行状态
        taskConfigurations[tid].status = TASK_STATUS_RUNNING;
        #if (KERNEL_USE_MPU == 1)	
        kerSetAppMpu(&taskConfigurations[tid]);        
        #endif
        return taskConfigurations[tid].stack_ptr;
    }
    else
    {
        //是否使用MPU保护内存单元
        #if (KERNEL_USE_MPU == 1)	
        kerSetIdleTaskMpu();
        #endif
        curTaskId = 0;
        return safeBgStackPtr;
    }
}

/**
* 查询下次需要运行的任务编号
*/
int32 Kernel_NextTask(void)
{
    uint8 tmpPri = 255;
    uint32 tmpTouch = 0xffffffff;
    uint8 idx;
    int32 r = -1;
    for(idx=0;idx<task_init_num;idx++)
    {
        Kernel_TickTasks(taskConfigurations+idx);
        
        if((taskConfigurations[idx].status == TASK_STATUS_READY) ||
            (taskConfigurations[idx].status == TASK_STATUS_RUNNING))
        {
            if(taskConfigurations[idx].priority < tmpPri)
            {
                tmpPri = taskConfigurations[idx].priority;
                tmpTouch = taskConfigurations[idx].touchtick;
                r = idx;
            }
            else if(taskConfigurations[idx].priority == tmpPri)
            {
                if(taskConfigurations[idx].touchtick < tmpTouch)
                {
                    tmpTouch = taskConfigurations[idx].touchtick;
                    r = idx;
                }
            }
            //else 优先级更低的就直接跳过
        }
    }
    return r;
}

/**
* @brief 每个TICK更新任务时间状态
*/
static void Kernel_TickTasks(TASK_CONTEXT *pTask)
{
    uint32 usedtick = KernelTick;
    int32 escaptick = usedtick - pTask->timtick;
   
    /*运行状态的任务不作该逻辑处理*/
    if((pTask->status == TASK_STATUS_RUNNING) ||
        (pTask->status == TASK_STATUS_INVALID))
    {
        return;
    }
    
    pTask->timtick = usedtick;    
    pTask->period_time -= escaptick;
    if(pTask->period_time < 0)
    {
        pTask->period_time += pTask->period;
        //周期时间已经到了，先设为就绪状态
        if(pTask->status == TASK_STATUS_WAIT)
        {
            pTask->status = TASK_STATUS_READY;
        }
    }
    
    if(pTask->wait_time > 0)
    {
        pTask->wait_time -= escaptick;
        if(pTask->wait_time <= 0)
        {
            //超时时间到达了，设置为就绪状态
            if(pTask->status == TASK_STATUS_WAIT)
            {
                pTask->status = TASK_STATUS_READY;
            }
        }
        else
        {
            //因为在等待状态，任务有效时，继续保持为等待；
            //即便是前阶段的周期时间已经到了
            if(pTask->status != TASK_STATUS_INVALID)
            {
                pTask->status = TASK_STATUS_WAIT;
            }
        }
    }    
}

TASK_CONTEXT *Kernel_GetCurTask(void)
{
    TASK_CONTEXT *pTsk = 0;
    __disable_irq();
    if(curTaskId > 0)
    {
        pTsk = &taskConfigurations[curTaskId - 1];
    }
     __enable_irq();
    return pTsk;
}

/**
* @descript: 以下为应用程序调用内核时的接口实现函数
*/
/**
* @brief 应用程序切入等待状态，并持续指定时间
*/
void kerTaskWait(uint32 ms)
{
    TASK_CONTEXT *pTsk;
    __disable_irq();
    if(curTaskId > 0)
    {
        pTsk = &taskConfigurations[curTaskId - 1];
        //设置当前任务等待时间，等待状态
        pTsk->wait_time = MS_TO_TICK(ms);
        pTsk->status = TASK_STATUS_WAIT;
        //启动一次任务切换
        SWITCH_TASK;
    }
    __enable_irq();
}

/**
* @brief 当前任务执行完成，等待下一次相位周期
*/
void kerTaskWaitNxtPeriod(void)
{
    TASK_CONTEXT *pTsk;
    __disable_irq();
    if(curTaskId > 0)
    {
        pTsk = &taskConfigurations[curTaskId - 1];
        //设置当前任务等待时间，等待状态
        pTsk->status = TASK_STATUS_WAIT;
        //启动一次任务切换
        SWITCH_TASK;
    }
     __enable_irq();
}

/**
* @brief 直接延迟一段时间，不释放CPU资源
*/
void kerTaskDelay(uint32 us)
{
    int32 tm_start = SysTick->VAL;
    int32 wait_clk = us * (SystemCoreClock / 1000000);
    int32 tm_end;
    int32 tm_diff;
    
    while(wait_clk > 0)
    {
        tm_end = SysTick->VAL;
        tm_diff = tm_start - tm_end;
        if(tm_diff < 0)
            tm_diff += SysTick->LOAD;
        tm_start = tm_end;
        
        wait_clk -= tm_diff;
    }
}

/**
* @brief 任务临时切换，并不挂起当前任务
*/
void kerTaskSwitch(void)
{
    SWITCH_TASK;
    __WFE();
}

/**
* @brief 删除当前任务
*/
void kerTaskKill(void)
{
    if(curTaskId > 0)
    {
        taskConfigurations[curTaskId-1].status = TASK_STATUS_INVALID;
    }
    
    {
        SWITCH_TASK;
        __WFE();
    }
}

/**
* @brief 获取系统时间，单位ms
*/
uint32 kerGetSystemTime(void)
{
    return KernelTick / (1000/ TICK_PERIOD);
}

uint32 KerGetSystemTick(void)
{
    return KernelTick;
}

uint16 kerCpuIdleMill = 0;

/** @brief 获取CPU占用率 千分比 */
uint16 KerGetCpuIdle(void)
{
    return kerCpuIdleMill;
}

/** 
* @brief 如果出现比当前优先级更高的任务，触发一次切换
*/
void kerActiveHighPrior(uint8 ckPri)
{
    if(curTaskId > 0)
    {
        if(taskConfigurations[curTaskId-1].priority > ckPri)
        {
            SWITCH_TASK;
        }
    }
    else
    {
        SWITCH_TASK;
    }
}
